﻿using AdminBase.Common.Helpers;
using AdminBase.Model;
using AdminBase.Model.Common;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using SqlSugar;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Unicode;

namespace AdminBase.webapi.Config
{
    /// <summary>
    /// 扩展类
    /// </summary>
    public static class HostBuilderExtend
    {
        /// <summary>
        /// 扩展注册类
        /// </summary>
        /// <param name="builder"></param>
        public static void Register(this WebApplicationBuilder builder)
        {
            builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());

            // 控制器加前缀
            builder.Services
                .AddControllers(option =>
                {
                    option.Conventions.Insert(0, new RouteConvention(new RouteAttribute("api/")));
                    //option.Filters.Add(typeof(IdempotentAttribute));  // 全局添加幂等性过滤器
                })
                .AddJsonOptions(options =>
                {
                    options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
                });

            builder.Services.AddEndpointsApiExplorer();

            #region 配置swagger中间件
            builder.Services.AddSwaggerGen(option =>
            {
                #region Swagger版本配置
                {
                    typeof(ApiVersions).GetEnumNames().ToList().ForEach(version =>
                    {
                        option.SwaggerDoc(version, new OpenApiInfo()
                        {
                            Title = $"版本：{version} Api文档",
                            Version = version,
                            Description = $"通用版本的CoreApi版本{version}"
                        });
                    });
                }
                #endregion

                #region 配置注释展示
                {
                    // xml文档绝对路径
                    var file = Path.Combine(AppContext.BaseDirectory, "AdminBase.webapi.xml");
                    // true: 显示控制器层注释
                    option.IncludeXmlComments(file, true);
                    // 对action的名称进行排序，如果有多个，就可以看见效果了
                    option.OrderActionsBy(o => o.RelativePath);
                }
                #endregion

                #region 扩展传入Token
                {
                    // 添加安全定义
                    option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                    {
                        Description = "请输入Token，格式为：Bearer XXXXXXXX(中间必须有空格)",
                        Name = "Authorization",
                        In = ParameterLocation.Header,
                        Type = SecuritySchemeType.ApiKey,
                        BearerFormat = "JWT",
                        Scheme = "Bearer"
                    });
                    // 添加安全要求
                    option.AddSecurityRequirement(new OpenApiSecurityRequirement {
                        {
                            new OpenApiSecurityScheme
                            {
                                Reference=new OpenApiReference()
                                {
                                    Type=ReferenceType.SecurityScheme,
                                    Id="Bearer"
                                }
                            },
                            new string[]{}
                        }
                    });
                }
                #endregion
            });
            #endregion

            var _dbconnection = builder.Configuration.GetSection("DBConnection:SqlServer").GetSection("Connection").Value;
            builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
            {
                #region 注册sqlsugar
                builder.Register<ISqlSugarClient>(context =>
                {
                    SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
                    {
                        // 连接字符串
                        ConnectionString = _dbconnection, // 数据库连接字符串
                        DbType = DbType.SqlServer, // 数据库类型
                        IsAutoCloseConnection = true, // 是否自动关闭连接
                        InitKeyType = InitKeyType.Attribute // 从特性中读取主键和自增列信息
                    });
                    //支持sql语句的输出，方便排查问题
                    db.Aop.OnLogExecuted = (sql, par) =>
                    {
                        Console.WriteLine("\r\n");
                        Console.WriteLine($"{DateTime.Now.ToString("yyyyMMdd HH:mm:ss")}，Sql语句：{sql}");
                        Console.WriteLine("===========================================================================");
                    };

                    return db;
                });
                #endregion

                //注册接口和实现层
                builder.RegisterModule(new AutofacModuleRegister());
            });

            //Automapper映射
            builder.Services.AddAutoMapper(typeof(AutoMapperConfigs));

            //第一步，注册JWT，读取配置文件appsettings.json中的JWTTokenOptions
            builder.Services.Configure<JWTTokenOptions>(builder.Configuration.GetSection("JWTTokenOptions"));
            #region JWT校验
            //第二步，增加鉴权逻辑
            JWTTokenOptions tokenOptions = new JWTTokenOptions();
            builder.Configuration.Bind("JWTTokenOptions", tokenOptions);
            builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)//Scheme渠道
             .AddJwtBearer(options =>  //这里是配置的鉴权的逻辑
             {
                 options.TokenValidationParameters = new TokenValidationParameters
                 {
                     //JWT有一些默认的属性，就是给鉴权时就可以筛选了
                     ValidateIssuer = true,//是否验证Issuer
                     ValidateAudience = true,//是否验证Audience
                     ValidateLifetime = true,//是否验证失效时间
                     ValidateIssuerSigningKey = true,//是否验证SecurityKey
                     ValidAudience = tokenOptions.Audience,//
                     ValidIssuer = tokenOptions.Issuer,//Issuer，这两项和前面签发jwt的设置一致
                     IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenOptions.SecurityKey))//拿到SecurityKey 
                 };
             });
            #endregion

            #region Redis配置
            //redis缓存
            var redisSection = builder.Configuration.GetSection("RedisConnection:Default");
            //连接字符串
            string _redisConnectionString = redisSection.GetSection("Connection").Value;
            //实例名称
            string _redisInstanceName = redisSection.GetSection("InstanceName").Value;
            //默认数据库 
            int _redisDefaultDB = int.Parse(redisSection.GetSection("DefaultDB").Value ?? "0");
            // 将 Redis 实例注册到依赖注入容器中
            builder.Services.AddSingleton(new RedisHelper(_redisConnectionString, _redisInstanceName, _redisDefaultDB));
            #endregion

            //添加跨域策略
            builder.Services.AddCors(options =>
            {
                options.AddPolicy(
                    "CorsPolicy",
                    opt => opt
                    .AllowAnyOrigin() // 允许来自任何源的请求。等同于WithOrigins("*")
                    .AllowAnyHeader() // 允许所有请求头。等同于WithHeaders("*")
                    .AllowAnyMethod() // 允许所有HTTP方法的请求。等同于WithMethods("*")
                    .WithExposedHeaders("X-Pagination"));
            });

            //设置Json返回的日期格式
            builder.Services.AddControllers().AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
            });

            // 默认配置
            builder.Services.Configure<DefaultSettings>(builder.Configuration.GetSection("DefaultSettings"));

            #region 分布式缓存

            //分布式 SQL Server 缓存
            //builder.Services.AddDistributedSqlServerCache(opt =>
            //{
            //    //Configuration.GetConnectionString("DefaultConnection")
            //    opt.ConnectionString = _dbconnection;
            //    opt.SchemaName = "dbo";
            //    opt.TableName = "CacheTable";
            //    opt.DefaultSlidingExpiration = TimeSpan.FromMinutes(2);
            //    opt.ExpiredItemsDeletionInterval = TimeSpan.FromMinutes(1);
            //});

            //分布式 Redis 缓存
            string redisDistributedCacheConnectionString = redisSection.GetSection("RedisConnection:DistributedCache").Value;
            builder.Services.AddDistributedRedisCache(cfg =>
            {
                cfg.Configuration = redisDistributedCacheConnectionString;
                cfg.InstanceName = "SampleInstance";
            });

            //分布式 StackExchangeRedis 缓存 
            //builder.Services.AddStackExchangeRedisCache(options =>
            //{
            //    options.Configuration = "localhost";
            //    options.InstanceName = "SampleInstance";
            //});

            //分布式缓存
            //builder.Services.AddDistributedMemoryCache();

            #endregion
        }
    }
}
